
#include "resmgr.h"
#include <d2d1.h>
#include <d2d1helper.h>
#include <wincodec.h>
#include <dwrite.h>
#pragma comment(lib,"d2d1.lib")
#pragma comment(lib,"dwrite.lib")

//已删除部分注释

//Utility
//////////////////////////////////////////////////////////////////////////
template <class T> void SafeRelease(T **ppT)
{
	if (*ppT)
	{
		(*ppT)->Release();
		*ppT = NULL;
	}
}

ID2D1Bitmap* WicLoadD2dBitmap(WCHAR* Path,IWICImagingFactory* pIWICFactory,ID2D1RenderTarget* pRenderTarget)
{
	//https://docs.microsoft.com/en-us/windows/win32/Direct2D/how-to-load-a-direct2d-bitmap-from-a-file
	//https://docs.microsoft.com/en-us/windows/win32/wic/-wic-bitmapsources-howto-drawusingd2d
	//https://docs.microsoft.com/en-us/windows/win32/wic/-wic-bitmapsources-howto-scale

	//加载图像并解码，如果从资源加载，可以用CreateDecoderFromStream
	IWICBitmapDecoder* pDecoder=NULL;
	HRESULT hr=pIWICFactory->CreateDecoderFromFilename(Path,NULL,GENERIC_READ,WICDecodeMetadataCacheOnLoad,&pDecoder);
	if (!SUCCEEDED(hr))
		return NULL;

	//获取第一帧，因为静态图像只有1帧
	IWICBitmapFrameDecode* pSource=NULL;
	pDecoder->GetFrame(0,&pSource);

	//如果需要修改图像数据，应该由IWICImagingFactory::CreateXXX()这一系列方法获得对应接口，如CreateBitmapScaler()
	//然后调用接口的Initialize指定参数，并与源数据IWICBitmapFrameDecode合成（这些接口都继承自IWICBitmapSource）
	//后面进行IWICFormatConverter::Initialize()时，如果需要应用修改，传入对应的接口，否则仍然用IWICBitmapFrameDecode

	//D2D只能使用32bppPBGRA格式绘制，需要进行转换(DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED)
	IWICFormatConverter* pConverter=NULL;
	pIWICFactory->CreateFormatConverter(&pConverter);
	pConverter->Initialize(pSource,GUID_WICPixelFormat32bppPBGRA,WICBitmapDitherTypeNone,NULL,0.0f,WICBitmapPaletteTypeCustom);

	//最后从转换后的Bitmap数据创建可绘制的ID2D1Bitmap对象（可能是因为ID2D1RenderTarget与设备相关）
	ID2D1Bitmap* pBitmap=NULL;
	pRenderTarget->CreateBitmapFromWicBitmap(pConverter,NULL,&pBitmap);

	//释放相关资源（好像都与当前资源绑定，没法重复利用）
	SafeRelease(&pDecoder);
	SafeRelease(&pSource);
	SafeRelease(&pConverter);
	return pBitmap;
}

void WicUnloadBitmap(ID2D1Bitmap* pBitmap)
{
	if (pBitmap!=NULL)
		pBitmap->Release();
}



//GResourceManager
//////////////////////////////////////////////////////////////////////////
enum ResType_t
{
	ResImage,
	ResAnimation,
	ResScale9,
	ResFont,
	ResCustom,
};

struct D2dRes_t
{
	WCHAR* Path;
	ID2D1Bitmap* ResObj;
	int D2dRefCount;
	int D2dType;
};

struct ResBase_t 
{
	WCHAR* Name;
	ResType_t Type;
	D2dRes_t* Source;
	int RefCount;
};

struct ImageR_t : public ResBase_t
{
	//Image，Animation，Sacle9均支持原始比例绘制和缩放绘制
	int Width;
	int Height;
	PVOID Attr;
};

struct ImageAttr 
{
	//Image支持有效区域在资源图的任意位置
	int X;
	int Y;
};

struct AnimationAttr 
{
	//Animation支持跳帧和暂停
	int CurrFrame;
	DWORD LastUpdateTime;
	int TotalFrame;
	int DelayTimeMS;
	BOOL Playing;
};

struct Scale9Attr
{
	//Scale9专为优化绘制质量，本身就很复杂
	// -------------
	// | 0 | 1 | 2 |
	// -------------
	// | 3 | 4 | 5 |
	// -------------
	// | 6 | 7 | 8 |
	// -------------
	int LeftSize;
	int TopSize;
	int RightSize;
	int BottomSize;
	RECT Split[9];
};

struct FontR_t : public ResBase_t
{
	//WCHAR* Famliy;
	int FontSize;
	int StrokeWidth;
	int BoxSize;
	D2dRes_t* StrokeRes;
};

GResourceManager::GResourceManager()
{
	//D2dResCache.comp=wstrless;
	//ObjectCache.comp=wstrless;
}

GResourceManager::~GResourceManager()
{
	std::map<WCHAR*,ResBase_t*,wstrless_t>::iterator it1;
	for (it1=ObjectCache.begin();it1!=ObjectCache.end();it1++)
	{
		ResBase_t* ResObj=(*it1).second;
		//map::clear()使用next节点遍历，不需要对比key
		delete[] ResObj->Name;
		//没有虚析构函数，通过类型确定释放方式
		if (ResObj->Type==ResFont)
		{
			delete (FontR_t*)ResObj;
		}
		else
		{
			ImageR_t* ImgResObj=(ImageR_t*)ResObj;
			if (ResObj->Type==ResImage)
				delete (ImageAttr*)ImgResObj->Attr;
			else if (ResObj->Type==ResAnimation)
				delete (AnimationAttr*)ImgResObj->Attr;
			else if (ResObj->Type==ResScale9)
				delete (Scale9Attr*)ImgResObj->Attr;
			delete ImgResObj;
		}
	}
	ObjectCache.clear();

	//清理所有已记录的资源，忽略引用计数
	std::map<WCHAR*,D2dRes_t*,wstrless_t>::iterator it2;
	for (it2=D2dResCache.begin();it2!=D2dResCache.end();it2++)
	{
		D2dRes_t* D2dRes=(*it2).second;
		delete[] D2dRes->Path;
		WicUnloadBitmap(D2dRes->ResObj);
		delete D2dRes;
	}
	D2dResCache.clear();
}

void GResourceManager::ReloadInvalidResource()
{
	//设备或系统变动时，释放原来无效的D2D资源，重新加载
	//假定第一次成功加载的资源第二次仍能成功加载
	std::map<WCHAR*,D2dRes_t*,wstrless_t>::iterator it;
	for (it=D2dResCache.begin();it!=D2dResCache.end();it++)
	{
		D2dRes_t* D2dRes=(*it).second;
		WicUnloadBitmap(D2dRes->ResObj);
		D2dRes->ResObj=WicLoadD2dBitmap(D2dRes->Path,D2dMgr->WicFactory,D2dMgr->D2dTarget);
	}
}

D2dRes_t* GResourceManager::FindD2dRes(WCHAR* Path)
{
	std::map<WCHAR*,D2dRes_t*,wstrless_t>::iterator it;
	it=D2dResCache.find(Path);
	if (it!=D2dResCache.end())
		return (*it).second;
	return NULL;
}

ResBase_t* GResourceManager::FindResObj(WCHAR* Name)
{
	//不能在这个函数检查类型
	//否则要么类型冲突时返回NULL，无法和未加载区分
	//要么类型冲突时返回Obj，还要在外面检查一次类型
	std::map<WCHAR*,ResBase_t*,wstrless_t>::iterator it;
	it=ObjectCache.find(Name);
	if (it!=ObjectCache.end())
		return (*it).second;
	return NULL;
}

D2dRes_t* GResourceManager::LoadD2dRes(WCHAR* Path)
{
	D2dRes_t* D2dRes=FindD2dRes(Path);
	//只有ID2D1Bitmap*一种，无需验证类型
	if (D2dRes!=NULL)
	{
		D2dRes->D2dRefCount++;
		return D2dRes;
	}
	ID2D1Bitmap* D2dBmp=WicLoadD2dBitmap(Path,D2dMgr->WicFactory,D2dMgr->D2dTarget);
	if (D2dBmp==NULL)
		return NULL;
	D2dRes=new D2dRes_t;
	D2dRes->Path=wstrdup(Path);
	D2dRes->ResObj=D2dBmp;
	D2dRes->D2dType=0;
	D2dRes->D2dRefCount=1;
	D2dResCache.insert(std::make_pair(D2dRes->Path,D2dRes));
	return D2dRes;
}

void GResourceManager::ReleaseD2dRes(D2dRes_t* D2dRes)
{
	//只有ID2D1Bitmap*一种，无需验证类型
	if (D2dRes!=NULL)
	{
		D2dRes->D2dRefCount--;
		if (D2dRes->D2dRefCount==0)
		{
			D2dResCache.erase(D2dRes->Path);
			delete[] D2dRes->Path;
			WicUnloadBitmap(D2dRes->ResObj);
			delete D2dRes;
		}
	}
}

ImageR_t* GResourceManager::LoadImageR(WCHAR* Name)
{
	ImageR_t* ResObj=(ImageR_t*)FindResObj(Name);
	if (ResObj!=NULL && ResObj->Type==ResImage)
	{
		//对象没有增加，D2dRefCount不变
		ResObj->RefCount++;
		return ResObj;
	}
	return NULL;
}

ImageR_t* GResourceManager::LoadImageR(WCHAR* Name,WCHAR* Path,int X,int Y,int Width,int Height)
{
	//如果已经加载，增加引用计数，返回现存的
	ImageR_t* ResObj=(ImageR_t*)FindResObj(Name);
	if (ResObj!=NULL)
	{
		//类型冲突无法加载
		if (ResObj->Type!=ResImage)
			return NULL;
		ResObj->RefCount++;
		return ResObj;
	}
	//如果没有现存对象，准备引用现存资源，或新加载资源
	D2dRes_t* D2dRes=LoadD2dRes(Path);
	if (D2dRes==NULL)
		return NULL;
	//调整参数，显示区域为整个图像时，可以省略宽高
	if (X<0)
		X=0;
	if (Y<0)
		Y=0;
	if (Width>D2dRes->ResObj->GetSize().width)
		Width=D2dRes->ResObj->GetSize().width;
	if (Height>D2dRes->ResObj->GetSize().height)
		Height=D2dRes->ResObj->GetSize().height;
	if (Width<=0)
	{
		X=0;
		Width=D2dRes->ResObj->GetSize().width;
	}
	if (Height<=0)
	{
		Y=0;
		Height=D2dRes->ResObj->GetSize().height;
	}
	//创建新对象，填充通用属性
	ResObj=new ImageR_t;
	ResObj->Name=wstrdup(Name);
	ResObj->Source=D2dRes;
	ResObj->RefCount=1;
	ResObj->Type=ResImage;
	ResObj->Width=Width;
	ResObj->Height=Height;
	//填充对象独立属性
	ImageAttr* Attr=new ImageAttr;
	Attr->X=X;
	Attr->Y=Y;
	ResObj->Attr=Attr;
	//加入容器
	ObjectCache.insert(std::make_pair(ResObj->Name,ResObj));
	return ResObj;
}

void GResourceManager::ReleaseImageR(ImageR_t* ResObj)
{
	if (ResObj!=NULL && ResObj->Type==ResImage)
	{
		ResObj->RefCount--;
		if (ResObj->RefCount==0)
		{
			ObjectCache.erase(ResObj->Name);
			delete[] ResObj->Name;
			D2dRes_t* D2dRes=ResObj->Source;
			delete (ImageAttr*)ResObj->Attr;
			delete ResObj;
			//引用计数为0时，销毁Image对象，但不一定卸载对应的资源，比如多个Image对象同时使用一张图片资源的不同区域
			//这些Image对象全部销毁时，图片资源的引用计数才会变为0，此时由下层函数自动卸载图片资源
			ReleaseD2dRes(D2dRes);
		}
	}
}

ImageR_t* GResourceManager::LoadAnimationR(WCHAR* Name)
{
	ImageR_t* ResObj=(ImageR_t*)FindResObj(Name);
	if (ResObj!=NULL && ResObj->Type==ResAnimation)
	{
		ResObj->RefCount++;
		return ResObj;
	}
	return NULL;
}

ImageR_t* GResourceManager::LoadAnimationR(WCHAR* Name,WCHAR* Path,int AniWidth,int AniHeight,int TotalFrame,int DelayTimeMS)
{
	//如果已经加载，增加引用计数，返回现存的
	ImageR_t* ResObj=(ImageR_t*)FindResObj(Name);
	if (ResObj!=NULL)
	{
		//类型冲突无法加载
		if (ResObj->Type!=ResAnimation)
			return NULL;
		ResObj->RefCount++;
		return ResObj;
	}
	//如果没有现存对象，准备引用现存资源，或新加载资源
	D2dRes_t* D2dRes=LoadD2dRes(Path);
	if (D2dRes==NULL)
		return NULL;
	//调整参数，显示区域为整个图像时，可以忽略宽高
	if (AniWidth<=0)
		AniWidth=D2dRes->ResObj->GetSize().width;
	if (AniHeight<=0)
		AniHeight=D2dRes->ResObj->GetSize().height;
	if (TotalFrame<=0)
		TotalFrame=1;
	if (DelayTimeMS==0)
		DelayTimeMS=UpdateTime;
	//创建新对象，填充通用属性
	ResObj=new ImageR_t;
	ResObj->Name=wstrdup(Name);
	ResObj->Source=D2dRes;
	ResObj->RefCount=1;
	ResObj->Type=ResAnimation;
	ResObj->Width=AniWidth;
	ResObj->Height=AniHeight;
	//填充对象独立属性
	AnimationAttr* Attr=new AnimationAttr;
	Attr->TotalFrame=TotalFrame;
	Attr->DelayTimeMS=DelayTimeMS;
	Attr->LastUpdateTime=0;
	Attr->CurrFrame=0;	
	Attr->Playing=TRUE;
	ResObj->Attr=Attr;
	//加入容器
	ObjectCache.insert(std::make_pair(ResObj->Name,ResObj));
	return ResObj;
}

void GResourceManager::ReleaseAnimationR(ImageR_t* ResObj)
{
	if (ResObj!=NULL && ResObj->Type==ResAnimation)
	{
		ResObj->RefCount--;
		if (ResObj->RefCount==0)
		{
			ObjectCache.erase(ResObj->Name);
			delete[] ResObj->Name;
			D2dRes_t* D2dRes=ResObj->Source;
			delete (AnimationAttr*)ResObj->Attr;
			delete ResObj;
			ReleaseD2dRes(D2dRes);
		}
	}
}

void GResourceManager::UpdateAllAnimationRFrame()
{
	std::map<WCHAR*,ResBase_t*,wstrless_t>::iterator it;
	for (it=ObjectCache.begin();it!=ObjectCache.end();it++)
	{
		if (it->second->Type==ResAnimation)
		{
			ImageR_t* ResObj=(ImageR_t*)it->second;
			AnimationAttr* Attr=(AnimationAttr*)ResObj->Attr;
			DWORD TimeStamp=GetTickCount();
			//前进的帧数只取整数，可能有1到2帧的误差
			//GetTickCount()和WM_TIMER本身就不算精确，无法强求完全准确
			int Period=(TimeStamp-Attr->LastUpdateTime)/Attr->DelayTimeMS;
			if (Period>0)
			{
				if (Attr->Playing)
				{
					Attr->CurrFrame+=Period;
					Attr->CurrFrame%=Attr->TotalFrame;
				}
				//即使暂停也必须更新时间，否则再次播放时会出现突进
				Attr->LastUpdateTime=TimeStamp;
			}
		}
	}
}

ImageR_t* GResourceManager::LoadScale9R(WCHAR* Name)
{
	ImageR_t* ResObj=(ImageR_t*)FindResObj(Name);
	if (ResObj!=NULL && ResObj->Type==ResScale9)
	{
		ResObj->RefCount++;
		return ResObj;
	}
	return NULL;
}

ImageR_t* GResourceManager::LoadScale9R(WCHAR* Name,WCHAR* Path,int LeftSize,int TopSize,int RightSize,int BottomSize)
{
	//如果已经加载，增加引用计数，返回现存的
	ImageR_t* ResObj=(ImageR_t*)FindResObj(Name);
	if (ResObj!=NULL)
	{
		//类型冲突无法加载
		if (ResObj->Type!=ResScale9)
			return NULL;
		ResObj->RefCount++;
		return ResObj;
	}
	//如果没有现存对象，准备引用现存资源，或新加载资源
	D2dRes_t* D2dRes=LoadD2dRes(Path);
	if (D2dRes==NULL)
		return NULL;
	//创建新对象，填充通用属性
	ResObj=new ImageR_t;
	ResObj->Name=wstrdup(Name);
	ResObj->Source=D2dRes;
	ResObj->RefCount=1;
	ResObj->Type=ResScale9;
	//Scale9加载时有默认尺寸，等价于普通Image
	ResObj->Width=D2dRes->ResObj->GetSize().width;
	ResObj->Height=D2dRes->ResObj->GetSize().height;
	//填充对象独立属性
	Scale9Attr* Attr=new Scale9Attr;
	Attr->LeftSize=LeftSize;
	Attr->TopSize=TopSize;
	Attr->RightSize=RightSize;
	Attr->BottomSize=BottomSize;
	int X[4]={0,LeftSize,D2dRes->ResObj->GetSize().width-RightSize,D2dRes->ResObj->GetSize().width};
	int Y[4]={0,TopSize,D2dRes->ResObj->GetSize().height-BottomSize,D2dRes->ResObj->GetSize().height};
	for (int i=0;i<9;i++)
	{
		Attr->Split[i].left=X[i%3];
		Attr->Split[i].top=Y[i/3];
		//实测D2D矩形右侧和底部的线在矩形之外，不需要-1
		Attr->Split[i].right=X[i%3+1];
		Attr->Split[i].bottom=Y[i/3+1];
	}
	ResObj->Attr=Attr;
	//加入容器
	ObjectCache.insert(std::make_pair(ResObj->Name,ResObj));
	return ResObj;
}

void GResourceManager::ReleaseScale9R(ImageR_t* ResObj)
{
	if (ResObj!=NULL && ResObj->Type==ResScale9)
	{
		ResObj->RefCount--;
		if (ResObj->RefCount==0)
		{
			ObjectCache.erase(ResObj->Name);
			delete[] ResObj->Name;
			D2dRes_t* D2dRes=ResObj->Source;
			delete (Scale9Attr*)ResObj->Attr;
			delete ResObj;
			ReleaseD2dRes(D2dRes);
		}
	}
}

FontR_t* GResourceManager::LoadFontR(WCHAR* Name)
{
	FontR_t* ResObj=(FontR_t*)FindResObj(Name);
	if (ResObj!=NULL && ResObj->Type==ResFont)
	{
		ResObj->RefCount++;
		return ResObj;
	}
	return NULL;
}

FontR_t* GResourceManager::LoadFontR(WCHAR* Name,WCHAR* Path,WCHAR* StrokePath,int Size,int StrokeWidth)
{
	//如果已经加载，增加引用计数，返回现存的
	FontR_t* ResObj=(FontR_t*)FindResObj(Name);
	if (ResObj!=NULL)
	{
		//类型冲突无法加载
		if (ResObj->Type!=ResFont)
			return NULL;
		ResObj->RefCount++;
		return ResObj;
	}
	//如果没有现存对象，准备引用现存资源，或新加载资源
	D2dRes_t* D2dRes=LoadD2dRes(Path);
	if (D2dRes==NULL)
		return NULL;
	//创建新对象，填充通用属性
	ResObj=new FontR_t;
	ResObj->Name=wstrdup(Name);
	ResObj->Source=D2dRes;
	ResObj->RefCount=1;
	ResObj->Type=ResFont;
	//填充对象独立属性
	ResObj->FontSize=Size;
	ResObj->StrokeWidth=StrokeWidth;
	ResObj->BoxSize=Size+StrokeWidth*2;	//等宽字体，且宽高相同
	if (StrokePath!=NULL)
		ResObj->StrokeRes=LoadD2dRes(StrokePath);	//加载失败时为NULL
	else
		ResObj->StrokeRes=NULL;
	ObjectCache.insert(std::make_pair(ResObj->Name,ResObj));
	return ResObj;
}

void GResourceManager::ReleaseFontR(FontR_t* ResObj)
{
	if (ResObj!=NULL && ResObj->Type==ResFont)
	{
		ResObj->RefCount--;
		if (ResObj->RefCount==0)
		{
			ObjectCache.erase(ResObj->Name);
			delete[] ResObj->Name;
			D2dRes_t* D2dRes=ResObj->Source;
			D2dRes_t* StrokeRes=ResObj->StrokeRes;
			delete ResObj;
			//D2dRes和StrokeRes的缓存和引用计数相互独立，可能一个释放了另一个还被引用
			//只要保证LoadFontR()和ReleaseFontR()成对调用，就不会出问题
			//ReleaseD2dRes()会判断StrokeRes是否为NULL
			ReleaseD2dRes(D2dRes);
			ReleaseD2dRes(StrokeRes);
		}
	}
}

void GResourceManager::ReleaseImageNoType(ImageR_t* ImageR)
{
	//设计的不好，不该出现这种代码
	if (ImageR->Type==ResImage)
		ReleaseImageR(ImageR);
	else if (ImageR->Type==ResAnimation)
		ReleaseAnimationR(ImageR);
	else if (ImageR->Type==ResScale9)
		ReleaseScale9R(ImageR);
}

int GResourceManager::GetImageWidth(ImageR_t* ImageR)
{
	return ImageR->Width;
}

int GResourceManager::GetImageHeight(ImageR_t* ImageR)
{
	return ImageR->Height;
}

int GResourceManager::GetFontSize(FontR_t* FontR)
{
	return FontR->FontSize;
}



//GDirect2dManager
//////////////////////////////////////////////////////////////////////////
GDirect2dManager::GDirect2dManager(){}
GDirect2dManager::~GDirect2dManager(){}

void GDirect2dManager::Init(HWND hWnd,int WinViewWidth,int WinViewHeight)
{
	this->hWnd=hWnd;
	this->WinViewWidth=WinViewWidth;
	this->WinViewHeight=WinViewHeight;
	ImageOpacity=1.0f;
	ColorArgb32=0xFFFFFFFF;
	OriginX=0;
	OriginY=0;

	//没有检测返回值，假设所有创建都能成功
	//WinViewWidth和WinViewHeight必须和Client Area一样大，否则绘制比例错误
	//另外窗口调整大小时会自动拉伸画面，可以在牺牲一定清晰度的前提下解决DPI问题
	CoInitialize(NULL);	
	D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,&D2dFactory);
	D2dFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),
		D2D1::HwndRenderTargetProperties(hWnd,D2D1::SizeU(WinViewWidth,WinViewHeight)),&D2dTarget);
	D2dTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
	D2dTarget->CreateSolidColorBrush(D2D1::ColorF(0.0f,0.0f,0.0f,1.0f),&D2dBrush);
	CoCreateInstance(CLSID_WICImagingFactory,NULL,CLSCTX_INPROC_SERVER,__uuidof(IWICImagingFactory),(void**)&WicFactory);

}

void GDirect2dManager::Uninit()
{
	//GDirect2dManager在程序最后清理资源，不检测引用计数
	//如果仍有其他对象持有资源，一定是出了bug
	WicFactory->Release();
	D2dBrush->Release();
	D2dTarget->Release();
	D2dFactory->Release();
	CoUninitialize();
}

void GDirect2dManager::ReadyPaint()
{
	D2dTarget->BeginDraw();
}

void GDirect2dManager::SubmitPaint()
{
	if (D2dTarget->EndDraw()==D2DERR_RECREATE_TARGET)
	{
		//按下Ctrl+Alt+Delete时，会导致设备对象失效，绘制失败
		//需要重新创建D2dTarget，并重新加载所有与之相关的资源
		//否则返回D2DERR_WRONG_RESOURCE_DOMAIN
		D2dTarget->Release();
		D2dFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),
			D2D1::HwndRenderTargetProperties(hWnd,D2D1::SizeU(WinViewWidth,WinViewHeight)),&D2dTarget);
		D2dTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
		D2dBrush->Release();
		D2dTarget->CreateSolidColorBrush(D2D1::ColorF(0.0f,0.0f,0.0f,1.0f),&D2dBrush);
		ResMgr->ReloadInvalidResource();
	}
}

void GDirect2dManager::Clear(DWORD ColorArgb32)
{
	float a=1.0f;
	float r=((ColorArgb32>>16)&0xFF)/255.0f;
	float g=((ColorArgb32>>8)&0xFF)/255.0f;
	float b=((ColorArgb32)&0xFF)/255.0f;
	D2dTarget->Clear(D2D1::ColorF(r,g,b,a));
}

void GDirect2dManager::SetColor(DWORD ColorArgb32)
{
	float a=((ColorArgb32>>24)&0xFF)/255.0f;
	float r=((ColorArgb32>>16)&0xFF)/255.0f;
	float g=((ColorArgb32>>8)&0xFF)/255.0f;
	float b=((ColorArgb32)&0xFF)/255.0f;
	this->ColorArgb32=ColorArgb32;
	D2dBrush->SetColor(D2D1::ColorF(r,g,b,a));
}

void GDirect2dManager::SetImageOpacity(float Opacity)
{
	Opacity=min(Opacity,1.0f);
	Opacity=max(Opacity,0.0f);
	ImageOpacity=Opacity;
}

void GDirect2dManager::DrawLine(int X1,int Y1,int X2,int Y2,int LineWidth)
{
	D2dTarget->DrawLine(D2D1::Point2F(X1,Y1),D2D1::Point2F(X2,Y2),D2dBrush,LineWidth);	
}

void GDirect2dManager::DrawRectangle(int X,int Y,int Width,int Height)
{
	D2dTarget->DrawRectangle(D2D1::RectF(X,Y,X+Width,Y+Height),D2dBrush,1.0f);
}

void GDirect2dManager::FillRectangle(int X,int Y,int Width,int Height)
{
	D2dTarget->FillRectangle(D2D1::RectF(X,Y,X+Width,Y+Height),D2dBrush);
}

void GDirect2dManager::DrawRoundRect(int X,int Y,int Width,int Height,int Radius)
{
	D2D1_ROUNDED_RECT RoundRect;
	RoundRect.rect=D2D1::RectF(X,Y,X+Width,Y+Height);
	RoundRect.radiusX=Radius;
	RoundRect.radiusY=Radius;
	D2dTarget->DrawRoundedRectangle(&RoundRect,D2dBrush,1.0f);
}

void GDirect2dManager::FillRoundRect(int X,int Y,int Width,int Height,int Radius)
{
	D2D1_ROUNDED_RECT RoundRect;
	RoundRect.rect=D2D1::RectF(X,Y,X+Width,Y+Height);
	RoundRect.radiusX=Radius;
	RoundRect.radiusY=Radius;
	D2dTarget->FillRoundedRectangle(&RoundRect,D2dBrush);
}

void GDirect2dManager::SetOrigin(int OriginX,int OriginY)
{
	this->OriginX=OriginX;
	this->OriginY=OriginY;
	D2dTarget->SetTransform(D2D1::Matrix3x2F::Translation(OriginX,OriginY));
}

void GDirect2dManager::PushClip(int X,int Y,int Width,int Height)
{
	//D2D的Clip有一些特性：调用Clip函数时，位置受Transform影响
	//调用Clip函数后再设置Transform，Clip区域自动调整与新原点的位置关系，保持其在屏幕上的位置不变
	//裁剪区域只支持实心矩形，如果应用了旋转变换，裁剪区域扩展为与坐标轴对齐的包围框
	//PushAxisAlignedClip和PopAxisAlignedClip必须成对使用
	//实测可以嵌套使用，内层的clip区域只会比外层小
	D2dTarget->PushAxisAlignedClip(D2D1::RectF(X,Y,X+Width,Y+Height),D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
}

void GDirect2dManager::PopClip()
{
	D2dTarget->PopAxisAlignedClip();
}

void GDirect2dManager::DrawImage(int X,int Y,ImageR_t* ImageR)
{
	DrawImage(X,Y,ImageR->Width,ImageR->Height,ImageR);
}

void GDirect2dManager::DrawImage(int X,int Y,int ScaleWidth,int ScaleHeight,ImageR_t* ImageR)
{
	if (ImageR==NULL || ImageR->Source->ResObj==NULL)
		return ;

	if (ImageR->Type==ResImage)
	{
		ImageAttr* Attr=(ImageAttr*)ImageR->Attr;

		D2D_RECT_F SrcRect;
		SrcRect.left=Attr->X;
		SrcRect.top=Attr->Y;
		SrcRect.right=Attr->X+ImageR->Width;
		SrcRect.bottom=Attr->Y+ImageR->Height;

		D2D_RECT_F DstRect;
		DstRect.left=X;
		DstRect.top=Y;
		DstRect.right=X+ScaleWidth;
		DstRect.bottom=Y+ScaleHeight;

		D2dTarget->DrawBitmap(ImageR->Source->ResObj,DstRect,ImageOpacity,D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,SrcRect);
	}
	else if (ImageR->Type==ResAnimation)
	{
		AnimationAttr* Attr=(AnimationAttr*)ImageR->Attr;

		int CountX=ImageR->Source->ResObj->GetSize().width/ImageR->Width;
		int CountY=ImageR->Source->ResObj->GetSize().height/ImageR->Height;
		int PosX=Attr->CurrFrame%CountX*ImageR->Width;
		int PosY=Attr->CurrFrame/CountX*ImageR->Height;

		D2D_RECT_F SrcRect;
		SrcRect.left=PosX;
		SrcRect.top=PosY;
		SrcRect.right=PosX+ImageR->Width;
		SrcRect.bottom=PosY+ImageR->Height;

		D2D_RECT_F DstRect;
		DstRect.left=X;
		DstRect.top=Y;
		DstRect.right=X+ScaleWidth;
		DstRect.bottom=Y+ScaleHeight;

		D2dTarget->DrawBitmap(ImageR->Source->ResObj,DstRect,ImageOpacity,D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,SrcRect);
	}
	else if (ImageR->Type==ResScale9)
	{
		if (ScaleWidth==ImageR->Width && ScaleHeight==ImageR->Height)
		{
			D2D_RECT_F SrcRect;
			SrcRect.left=0;
			SrcRect.top=0;
			SrcRect.right=ImageR->Width;
			SrcRect.bottom=ImageR->Height;

			D2D_RECT_F DstRect;
			DstRect.left=X;
			DstRect.top=Y;
			DstRect.right=X+ImageR->Width;
			DstRect.bottom=Y+ImageR->Height;

			D2dTarget->DrawBitmap(ImageR->Source->ResObj,DstRect,ImageOpacity,D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,SrcRect);
		}
		else
		{
			//todo：Scale9资源有最小尺寸限制，取决于4个角的大小
			Scale9Attr* Attr=(Scale9Attr*)ImageR->Attr;

			int DstX[4]={0,Attr->LeftSize,ScaleWidth-Attr->RightSize,ScaleWidth};
			int DstY[4]={0,Attr->TopSize,ScaleHeight-Attr->BottomSize,ScaleHeight};

			for (int i=0;i<9;i++)
			{
				D2D_RECT_F SrcRect;
				SrcRect.left=Attr->Split[i].left;
				SrcRect.top=Attr->Split[i].top;
				SrcRect.right=Attr->Split[i].right;
				SrcRect.bottom=Attr->Split[i].bottom;

				D2D_RECT_F DstRect;
				DstRect.left=DstX[i%3]+X;
				DstRect.top=DstY[i/3]+Y;
				DstRect.right=DstX[i%3+1]+X;
				DstRect.bottom=DstY[i/3+1]+Y;

				D2dTarget->DrawBitmap(ImageR->Source->ResObj,DstRect,ImageOpacity,D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,SrcRect);
			}
		}
	}
}

void GDirect2dManager::SetAnimationState(int FrameNum,BOOL Playing,ImageR_t* ImageR)
{
	if (ImageR!=NULL && ImageR->Type==ResAnimation)
	{
		AnimationAttr* Attr=(AnimationAttr*)ImageR->Attr;
		Attr->CurrFrame=FrameNum%Attr->TotalFrame;
		Attr->Playing=Playing;
	}
}

void GDirect2dManager::DrawText(WCHAR* Text,int Len,int X,int Y,FontR_t* FontR)
{
	if (FontR==NULL || FontR->Source->ResObj==NULL)
		return ;
	if (Len==-1)
		Len=wcslen(Text);

	//单纯计算数量时，允许字形少于65536个，宽高任意
	//但是绘制时以Unicode作为索引，要求每个资源里必须有65536字形
	//实际现有的资源都是256*256，可能以后会添加字符映射表，或固定排除一部分字符，以支持精简的字体资源
	int NumX=FontR->Source->ResObj->GetSize().width/FontR->BoxSize;
	int NumY=FontR->Source->ResObj->GetSize().height/FontR->BoxSize;

	//Direct2D要求必须使用此模式
	//https://learn.microsoft.com/en-us/windows/win32/direct2d/id2d1rendertarget-fillopacitymask
	D2dTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
	for (int i=0;i<Len;i++)
	{
		//文字主体尺寸为FontSize，位置偏移为StrokeWidth
		D2D_RECT_F SrcRect;
		SrcRect.left=Text[i]%NumX*FontR->BoxSize+FontR->StrokeWidth;
		SrcRect.top=Text[i]/NumX*FontR->BoxSize+FontR->StrokeWidth;
		SrcRect.right=SrcRect.left+FontR->FontSize;
		SrcRect.bottom=SrcRect.top+FontR->FontSize;
		//文字主体绘制位置就是X和Y
		//只绘制一行，首尾不留空，字与字之间可以留空
		D2D_RECT_F DstRect;
		DstRect.left=X;
		DstRect.top=Y;
		DstRect.right=X+FontR->FontSize;
		DstRect.bottom=Y+FontR->FontSize;
		D2dTarget->FillOpacityMask(FontR->Source->ResObj,D2dBrush,D2D1_OPACITY_MASK_CONTENT_GRAPHICS,&DstRect,&SrcRect);
		X+=GetCharWidth(FontR,Text[i]);
	}
	D2dTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
}

void GDirect2dManager::DrawTextWithBorder(WCHAR* Text,int Len,int X,int Y,DWORD StrokeColor,FontR_t* FontR)
{
	if (FontR==NULL || FontR->Source->ResObj==NULL)
		return ;
	if (Len==-1)
		Len=wcslen(Text);
	
	int NumX=FontR->Source->ResObj->GetSize().width/FontR->BoxSize;
	int NumY=FontR->Source->ResObj->GetSize().height/FontR->BoxSize;
	D2dTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);

	DWORD LastColor=ColorArgb32;
	if (StrokeColor!=0 && FontR->StrokeRes!=NULL)
	{
		SetColor(StrokeColor);
		int TempX=X;
		for (int i=0;i<Len;i++)
		{
			//描边尺寸为BoxSize
			D2D_RECT_F SrcRect;
			SrcRect.left=Text[i]%NumX*FontR->BoxSize;
			SrcRect.top=Text[i]/NumX*FontR->BoxSize;
			SrcRect.right=SrcRect.left+FontR->BoxSize;
			SrcRect.bottom=SrcRect.top+FontR->BoxSize;
			//描边对齐到X和Y
			D2D_RECT_F DstRect;
			DstRect.left=TempX-FontR->StrokeWidth;
			DstRect.top=Y-FontR->StrokeWidth;
			DstRect.right=DstRect.left+FontR->BoxSize;
			DstRect.bottom=DstRect.top+FontR->BoxSize;
			D2dTarget->FillOpacityMask(FontR->StrokeRes->ResObj,D2dBrush,D2D1_OPACITY_MASK_CONTENT_GRAPHICS,&DstRect,&SrcRect);
			TempX+=GetCharWidth(FontR,Text[i]);
		}
	}

	SetColor(LastColor);
	for (int i=0;i<Len;i++)
	{
		//文字主体尺寸为FontSize，位置偏移为StrokeWidth
		D2D_RECT_F SrcRect;
		SrcRect.left=Text[i]%NumX*FontR->BoxSize+FontR->StrokeWidth;
		SrcRect.top=Text[i]/NumX*FontR->BoxSize+FontR->StrokeWidth;
		SrcRect.right=SrcRect.left+FontR->FontSize;
		SrcRect.bottom=SrcRect.top+FontR->FontSize;
		//文字主体绘制位置就是X和Y
		D2D_RECT_F DstRect;
		DstRect.left=X;
		DstRect.top=Y;
		DstRect.right=X+FontR->FontSize;
		DstRect.bottom=Y+FontR->FontSize;
		D2dTarget->FillOpacityMask(FontR->Source->ResObj,D2dBrush,D2D1_OPACITY_MASK_CONTENT_GRAPHICS,&DstRect,&SrcRect);
		X+=GetCharWidth(FontR,Text[i]);
	}

	D2dTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
}

int GDirect2dManager::GetTextWidth(FontR_t* FontR,WCHAR* Text)
{
	int Len=wcslen(Text);
	int Width=0;
	for (int i=0;i<Len;i++)
		Width+=GetCharWidth(FontR,Text[i]);
	return Width;
}

int GDirect2dManager::GetCharWidth(FontR_t* FontR,WCHAR wch)
{
	//仅适用于等宽字体，粗略估算，可能有特例没考虑到
	if (wch=='\t')
		return FontR->FontSize*2;
	else if (wch=='\r' || wch=='\n')
		return 0;
	else if (wch<128)	//不能设256，分隔符·就是个反例，Index=0xB7
		return FontR->FontSize/2;
	else
		return FontR->FontSize;
}

int GDirect2dManager::GetFontHeight(FontR_t* FontR)
{
	//要求字体资源的宽高相同
	return FontR->FontSize;
}

void GDirect2dManager::AutoDrawText(WCHAR* Text,int Len,int X,int Y,int Width,int Height,int CharSpace,int LineSpace,FontR_t* FontR)
{
	if (FontR==NULL || FontR->Source->ResObj==NULL)
		return ;
	if (Len==-1)
		Len=wcslen(Text);

	int NumX=FontR->Source->ResObj->GetSize().width/FontR->BoxSize;
	int NumY=FontR->Source->ResObj->GetSize().height/FontR->BoxSize;

	D2dTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
	PushClip(X,Y,Width,Height);

	int CharHeight=GetFontHeight(FontR);
	int DrawX=0;
	int DrawY=0;
	int i=0;
	while (i<Len)
	{
		//注意条件不同，纵向最后一行即使位置不够也可以绘制一半
		//但是横向必须空间足够一个字符才绘制
		if (DrawY>=Height)
			break;
		int CharWidth=GetCharWidth(FontR,Text[i]);
		if (DrawX+CharWidth>=Width)	//不加等号效果会很差
		{
			DrawX=0;
			DrawY+=CharHeight;
			DrawY+=LineSpace;
			continue;
		}
		else if (Text[i]=='\n')
		{
			DrawX=0;
			DrawY+=CharHeight;
			DrawY+=LineSpace;
			i++;
			continue;
		}

		D2D_RECT_F SrcRect;
		SrcRect.left=Text[i]%NumX*FontR->BoxSize+FontR->StrokeWidth;
		SrcRect.top=Text[i]/NumX*FontR->BoxSize+FontR->StrokeWidth;
		SrcRect.right=SrcRect.left+FontR->FontSize;
		SrcRect.bottom=SrcRect.top+FontR->FontSize;

		D2D_RECT_F DstRect;
		DstRect.left=X+DrawX;
		DstRect.top=Y+DrawY;
		DstRect.right=X+DrawX+FontR->FontSize;
		DstRect.bottom=Y+DrawY+FontR->FontSize;
		D2dTarget->FillOpacityMask(FontR->Source->ResObj,D2dBrush,D2D1_OPACITY_MASK_CONTENT_GRAPHICS,&DstRect,&SrcRect);

		DrawX+=CharWidth;
		DrawX+=CharSpace;
		i++;
	}

	PopClip();
	D2dTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
}

int GDirect2dManager::CalcAutoDrawTextHeight(WCHAR* Text,int Len,int Width,int CharSpace,int LineSpace,FontR_t* FontR)
{
	//横向必须空间足够一个字符才绘制，否则Height将会无限大，一直循环卡死
	if (Width<FontR->FontSize)
		return -1;

	if (Len==-1)
		Len=wcslen(Text);
	int CharHeight=GetFontHeight(FontR);
	int DrawX=0;
	int DrawY=0;
	int i=0;
	while (i<Len)
	{
		int CharWidth=GetCharWidth(FontR,Text[i]);
		if (DrawX+CharWidth>Width)
		{
			DrawX=0;
			DrawY+=CharHeight;
			DrawY+=LineSpace;
			continue;
		}
		else if (Text[i]=='\n')
		{
			DrawX=0;
			DrawY+=CharHeight;
			DrawY+=LineSpace;
			i++;
			continue;
		}
		DrawX+=CharWidth;
		DrawX+=CharSpace;
		i++;
	}
	//最后一行结束时直接跳出循环，而且没有行距
	DrawY+=CharHeight;
	return DrawY;
}
